package robocup.component.coach;

import java.util.ArrayList;
import java.util.List;

/**
 * 
 * @author Felix Brossmann
 * 
 */
public class LinearRegression {

  // y = a + b*x

  List<Double> x_list;
  List<Double> y_list;

  double       a       = 0;
  double       b       = 0;

  boolean      changed = false; // new calculation of a and b necessary?

  // constructor
  public LinearRegression(
      final int capacity) {

    this.x_list = new ArrayList<Double>(capacity);
    this.y_list = new ArrayList<Double>(capacity);
  }

  public void addPair(final double x,
      final double y) {

    this.changed = true; // new value --> new calculation fo a and b nessecary

    this.x_list.add(x);
    this.y_list.add(y);
  }

  /**
   * removes all values from this calculation. both lists will be cleared
   */
  public void reset() {

    this.changed = true;

    this.a = 0;
    this.b = 0;

    this.x_list.clear();
    this.y_list.clear();

  }

  public double getA() {

    if (this.changed) {
      this.calculate();
    }

    return this.a;
  }

  public double getB() {

    if (this.changed) {
      this.calculate();
    }

    return this.b;
  }

  private void calculate() {

    // first calculate mean y and mean y
    double mean_x = 0;
    double mean_y = 0;

    for (int i = 0; i < this.x_list.size(); i++) {
      mean_x += this.x_list.get(i);
      mean_y += this.y_list.get(i);
    }

    mean_x /= this.x_list.size();
    mean_y /= this.y_list.size();

    // now calculate variance and covariance
    double variance = 0;
    double covariance = 0;

    for (int i = 0; i < this.x_list.size(); i++) {
      covariance = covariance + (this.x_list.get(i) - mean_x) * (this.y_list
          .get(i) - mean_y);
      variance = variance + (this.x_list.get(i) - mean_x) * (this.x_list.get(i) - mean_x);
    }

    this.b = covariance / variance;

    this.a = mean_y - this.b * mean_x;

    // values are calculated
    this.changed = false;
  }
}
